SPB Git

spb/earth-now Public License

earth-now.co — real-time planetary dashboard: live world metrics modeled, not streamed.

TypeScript 93% Shell 2.3% SQL 1.4% JavaScript 1.3% Dockerfile 1.2% CSS 0.8%
1.5 KB · 48 lines tsx
Raw Blame History
1/**2 * earth-now.co3 * Author:  Simon-Pierre Boucher4 * Contact: contact@spboucher.ai5 * File:    apps/web/app/metric/[id]/page.tsx6 * Purpose: Public per-metric page — live counter, real-time model chart and the metric's own methodology7 */89import type { Metadata } from "next";10import { notFound } from "next/navigation";11import MetricDetail from "@/components/MetricDetail";12import { fetchMetrics, fetchModels } from "@/lib/api";1314export const dynamic = "force-dynamic";1516interface Params {17  params: { id: string };18}1920export async function generateMetadata({ params }: Params): Promise<Metadata> {21  try {22    const metrics = await fetchMetrics();23    const metric = metrics.find((m) => m.id === params.id);24    if (metric === undefined) return { title: "earth-now.co" };25    return {26      title: `${metric.name.fr} — earth-now.co`,27      description: `${metric.name.fr} / ${metric.name.en} — compteur live piloté par un modèle statistique documenté (${metric.model}).`,28    };29  } catch {30    return { title: "earth-now.co" };31  }32}3334export default async function MetricPage({ params }: Params) {35  let metric;36  let model = null;37  try {38    const [metrics, models] = await Promise.all([fetchMetrics(), fetchModels()]);39    metric = metrics.find((m) => m.id === params.id);40    model = models.models[params.id] ?? null;41  } catch {42    // API down: 404 rather than a broken page (the dashboard has the offline state).43    notFound();44  }45  if (metric === undefined) notFound();46  return <MetricDetail metric={metric} model={model} />;47}48